import axios from 'axios'
// @ts-ignore
import qs from 'qs'
import type {
  AxiosInstance,
  AxiosRequestConfig,
  InternalAxiosRequestConfig,
  AxiosResponse,
} from 'axios'
import { _window } from '@/global.ts'
import { ElMessage } from 'element-plus'

// Message pop-up disappearance time
const MESSAGEDURATION = 1000
/**
 * request package by axios
 */
class Request {
  baseUrl: string | undefined
  request: AxiosInstance
  successCode: number = 0 // 请求成功返回的code

  constructor(
    baseUrl?: string,
    options?: AxiosRequestConfig,
    customInitInterceptors?: (_request: AxiosInstance) => void,
  ) {
    this.baseUrl = baseUrl
    this.request = axios.create({
      baseURL: baseUrl ?? '',
      timeout: 10000,
      ...options,
    })
    customInitInterceptors ? customInitInterceptors(this.request) : this.initInterceptors()
  }

  initInterceptors() {
    this.request.interceptors.request.use(
      (config: InternalAxiosRequestConfig<any>) => {
        if (config.method === 'post') {
          // 请求参数字符串化处理
          config.data = qs.stringify(config.data, {
            arrayFormat: 'brackets',
          })
        }
        return config
      },
      (err: any) => {
        _window._log.error(`requets error reason is ${err}`)
        return Promise.reject(err)
      },
    )

    /**
     * 返回报错，在这里做全局的错误提示
     * 返回数据格式为：{ code: 0, msg: '', data: '' }
     * 规则是当 code 为 0 时表示请求成功，为 其他值 时表示失败（其中 msg 描述时失败原因）
     * 以上可根据实际情况改动
     */
    this.request.interceptors.response.use(
      (response: AxiosResponse<any, any>) => {
        // blob|stream 类型的请求数据直接返回
        if (response.config.responseType === 'blob' || response.config.responseType === 'stream') {
          return response
        }
        if (+response.data.code === this.successCode) {
          return response.data
        } else {
          let code: number | string = +response.data.code
          if (code < 0) code = code + ''
          if (code in this.handleErroStatus) {
            const handle = this.handleErroStatus[code as keyof typeof this.handleErroStatus]
            return handle(response)
          }
          handleMessage(response.data.msg)
          return Promise.reject(response)
        }
      },
      (err: any) => {
        // 超出 2xx 范围的状态码都会触发该函数
        if (err.status in this.handleErroStatus) {
          const handle = this.handleErroStatus[err.status as keyof typeof this.handleErroStatus]
          return handle(err)
        }
        const message: string = err.message
        handleMessage(message)
        return Promise.reject(err)
      },
    )
  }
  /**
   * 请求错误码集中处理--可以配合后端定义特殊状态码进行对应处理
   * Request centralized processing of error codes
   * you can cooperate with the backend to define special status codes for corresponding processing
   */
  handleErroStatus = {
    400: function () {
      _window._log.error(`Bad Request. Please check the request parameters`)
      return Promise.reject()
    },
    '-7': function (_data: any) {
      handleMessage('登录状态已退出，请重新登录')
    },
    '-8': function () {
      handleMessage('登录验证失败，请重新登录')
    },
    '-4001': function () {
      handleMessage('无操作权限')
      _window.router.back()
    },
    500: function () {
      _window._log.error(`Internal Server Error`)
      return Promise.reject()
    },
  }
}

function handleMessage(msg: string) {
  let message: string = msg
  if (!msg) return
  if (msg === 'Network Error') {
    message = '后端网络故障'
  } else if (msg.includes('timeout')) {
    message = '接口请求超时'
  } else if (msg.includes('Request failed with status code')) {
    message = '接口' + msg.slice(-3) + '异常'
  }
  // console.log(message)
  // this can unified message prompt
  _window._log.error(`response error reason is ${message}`)
  // @ts-ignore
  ElMessage({ type: 'error', message: message, duration: MESSAGEDURATION })
}

export default Request
